#!/usr/bin/python

#    This file is part of CamVue.
#
#    CamVue is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    CamVue is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with CamVue.  If not, see <http://www.gnu.org/licenses/>.
#
#    Copyright 2012  Jeremy Mortis (mortis@tansay.ca)

import os
import sys
import v4l2
import errno
import fcntl
import select
import glob
import ctypes
import struct
import StringIO
import Image
import logging
import time

#--------------------------------------------------------------------
class Camera:

    def __init__(self, device=0, width=640, height=480):
        self.device = str(device)
        self.width = width
        self.height = height
        self.fd = None

        if sys.platform != 'linux2':
            raise Exception("This driver for Linux only (not %s)" % sys.platform)

        if self.device.isdigit():
            self.device = '/dev/video%s' % self.device

        self.fd = os.open(self.device, os.O_RDWR | os.O_NONBLOCK)

        format = v4l2.v4l2_format()
        format.type = v4l2.V4L2_BUF_TYPE_VIDEO_CAPTURE

        fcntl.ioctl(self.fd, v4l2.VIDIOC_G_FMT, format)

        format.fmt.pix.pixelformat = v4l2.V4L2_PIX_FMT_JPEG
        format.fmt.pix.field = v4l2.V4L2_FIELD_NONE
        format.fmt.pix.width = self.width
        format.fmt.pix.height = self.height
        format.fmt.pix.bytesperline = 0

        fcntl.ioctl(self.fd, v4l2.VIDIOC_S_FMT, format)

        logging.info("Camera initialized: %s" % self.device)

    def getImage(self):

        rlist, wlist, xlist = select.select([self.fd], [], [], 2.0)

        if len(rlist) > 0:
            buf = os.read(self.fd, 300000)
            logging.debug("Read %i bytes" % len(buf))
        else:
            logging.error("Device not ready")
            raise Exception("Device not ready")

        return Image.open(StringIO.StringIO(buf))

    def getProperties(self):

        p = {}

        p["Device:"] =  self.device

        if not self.fd:
            p["Status"] = "closed"
            return
        else:
            p["Status"] = "open"

        cap = v4l2.v4l2_capability()

        fcntl.ioctl(self.fd, v4l2.VIDIOC_QUERYCAP, cap)

        p["Driver"] = cap.driver
        p["Card"] = cap.card
        p["Bus info"] = cap.bus_info
        p["Version"] = cap.version
        p["Capabilities"] = "0x%08x" % cap.capabilities

        if (not (cap.capabilities & v4l2.V4L2_CAP_VIDEO_CAPTURE)):
            Exception("Not a video capture device")

        if (not (cap.capabilities & v4l2.V4L2_CAP_READWRITE)):
            Exception("Device does not support read i/o")

        format = v4l2.v4l2_format()
        format.type = v4l2.V4L2_BUF_TYPE_VIDEO_CAPTURE

        fcntl.ioctl(self.fd, v4l2.VIDIOC_G_FMT, format)
    
        p["Width"] = format.fmt.pix.width
        p["Height"] = format.fmt.pix.height
        p["Pixel format"] = struct.pack("I", format.fmt.pix.pixelformat)
        p["Field"] = format.fmt.pix.field
        p["Bytes per line"] = format.fmt.pix.bytesperline
        p["Image size"] = format.fmt.pix.sizeimage
        p["Colorspace"] = format.fmt.pix.colorspace

        streamparm = v4l2.v4l2_streamparm()
        streamparm.type = v4l2.V4L2_BUF_TYPE_VIDEO_CAPTURE

        fcntl.ioctl(self.fd, v4l2.VIDIOC_G_PARM, streamparm)
    
        p["Stream type"] = streamparm.type
        p["Stream capability"] = streamparm.parm.capture.capability
        p["Time per frame numerator"] = streamparm.parm.capture.timeperframe.numerator
        p["Time per frame denominator"] = streamparm.parm.capture.timeperframe.denominator
        p["Read buffers"] = streamparm.parm.capture.readbuffers

        return p
    
    def close(self):
        os.close(self.fd)

def getDeviceList():
    logging.info("Getting device list")
    devices = []
    for deviceFile in glob.glob('/dev/video*'):
        logging.info("Getting properties for: %s" % deviceFile)
        device = Camera(deviceFile)
        devices.append((deviceFile, device.getProperties()["Card"]))
        device.close()
    return devices

if __name__ == '__main__':
    print 'found ', len(getDeviceList()) , 'video device(s)'
    for device in getDeviceList():
        print device

    d = Camera(0, width=320, height=240)
    
    properties = d.properties()
    for s in properties:
        print s, ":", properties[s] 

#    i = d.getImage()
#    print type(i)
#    i.save("junk.jpg")
    start = time.time()
    for i in range(100):
        x = d.getImage()
        print time.time()
                                  
    print "Frame rate:", (time.time() - start) / 100

                                  

